﻿using InTheHand.Net.Sockets;
using System.IO;
using System.Text;

namespace BluetoothDemo.Internal
{
    public class PrinterManage
    {
        public static BluetoothClient CurrentBluetoothClient { get; set; }
        public static List<BluetoothDeviceInfo> DeviceList { get; set; }
        public static PrinterType PrinterType { get; set; } = PrinterType.i80mm;
        public static string PrinterName { get; set; }
        private static Stream Stream { get; set; } = null;
        private static bool FoundPrinter { get; set; } = false;

        /// <summary>
        /// 检索蓝牙打印机设备
        /// </summary>
        /// <returns></returns>
        public static async Task<List<BluetoothDeviceInfo>> FindListAsync()
        {
            try
            {
                FoundPrinter = false;

                await CheckBluetoothConnectedAsync();

                if (CurrentBluetoothClient == null)
                    CurrentBluetoothClient = new BluetoothClient();

                DeviceList = CurrentBluetoothClient.DiscoverDevices(5).ToList();

                if (DeviceList.Count == 0)
                    throw new Exception("找不到蓝牙打印机");

                FoundPrinter = true;

                return DeviceList;
            }
            catch (Exception erro)
            {
                throw erro;
            }
        }

        /// <summary>
        /// 检索配对的蓝牙打印机设备
        /// </summary>
        /// <returns></returns>
        public static async Task<List<BluetoothDeviceInfo>> FindPairedListAsync()
        {
            try
            {
                FoundPrinter = false;

                await CheckBluetoothConnectedAsync();

                if (CurrentBluetoothClient == null)
                    CurrentBluetoothClient = new BluetoothClient();

                DeviceList = CurrentBluetoothClient.PairedDevices.ToList();

                if (DeviceList.Count == 0)
                    throw new Exception("找不到配对的蓝牙打印机");

                FoundPrinter = true;

                await Task.Delay(0);

                return DeviceList;
            }
            catch (Exception erro)
            {
                throw erro;
            }
        }

        public static async Task<bool> ConnectAsync(string printerName, PrinterType printerType)
        {
            bool isConnect = false;

            try
            {
                PrinterName = printerName;
                PrinterType = printerType;

                if (await ConnectAsync())
                    await CloseAsync();

                if (!FoundPrinter)
                    await FindPairedListAsync();
                else
                    await CheckBluetoothConnectedAsync();

                if (DeviceList == null)
                    DeviceList = new List<BluetoothDeviceInfo>();

                if (DeviceList.Count == 0)
                    DeviceList = await FindPairedListAsync();

                var dispositivos = await Task.Run(() => DeviceList.Where(x => $"{x.DeviceName}".ToUpper().Equals(printerName.ToUpper())).FirstOrDefault());

                if (dispositivos == null)
                    throw new Exception("找不到要连接的打印机");

                if (CurrentBluetoothClient == null)
                    CurrentBluetoothClient = new BluetoothClient();

                await Task.Run(() => CurrentBluetoothClient.Connect(dispositivos.DeviceAddress, InTheHand.Net.Bluetooth.BluetoothService.SerialPort));

                await Task.Delay(1000);

                if (!CurrentBluetoothClient.Connected)
                    throw new Exception("无法连接打印机");

                Stream = await Task.Run(() => CurrentBluetoothClient.GetStream());

                if (Stream == null)
                    throw new Exception("无法连接打印机");

                isConnect = true;
            }
            catch (Exception erro)
            {
                throw erro;
            }

            return isConnect;
        }

        public static async Task<bool> SendAsync(byte[] dados)
        {
            bool resposta = false;

            try
            {
                if (dados == null)
                    return resposta;

                await CheckBluetoothConnectedAsync();
                await VerificarSeDispositivoConectadoAsync(false);

                if (!CurrentBluetoothClient.Connected)
                    await ConnectAsync(PrinterName, PrinterType);

                if (Stream == null)
                    throw new Exception("无法将数据发送到打印机。连接未打开");

                var partesDadosBytes = await QuebrarBytesEmBlocosAsync(dados, 1000);

                foreach (byte[] dadoBytes in partesDadosBytes)
                {
                    await SendBytesAsync(dadoBytes, 0, dadoBytes.Length);
                    await Task.Delay(7);
                }
            }
            catch (Exception erro)
            {
                throw erro;
            }

            return resposta;
        }

        public static async Task<bool> SendAsync(byte[] buffer, int offset, int count)
        {
            bool resposta = false;

            try
            {
                if (buffer == null)
                    return resposta;

                await CheckBluetoothConnectedAsync();
                await VerificarSeDispositivoConectadoAsync(false);

                if (!CurrentBluetoothClient.Connected)
                    await ConnectAsync(PrinterName, PrinterType);

                if (Stream == null)
                    throw new Exception("无法将数据发送到打印机。连接未打开");

                await SendBytesAsync(buffer, offset, count);
            }
            catch (Exception erro)
            {
                throw erro;
            }

            return resposta;
        }

        public static async Task<bool> SendAsync(string texto)
        {
            bool resposta = false;

            try
            {
                if (string.IsNullOrEmpty(texto))
                    return resposta;

                var dados = Encoding.UTF8.GetBytes(texto);
                await SendAsync(dados);
            }
            catch (Exception erro)
            {
                throw erro;
            }

            return resposta;
        }

        private static async Task SendBytesAsync(byte[] buffer, int offset, int count)
        {
            await Task.Run(() => Stream.Write(buffer, offset, count));
        }

        public static async Task CloseAsync()
        {
            try
            {
                await CheckBluetoothConnectedAsync();
                await VerificarSeDispositivoConectadoAsync();

                await Task.Run(() => CurrentBluetoothClient.Close());

                await Task.Delay(1000);
            }
            catch (Exception erro)
            {
                //throw erro;
            }
        }

        public static async Task<bool> ConnectAsync()
        {
            bool response = false;

            try
            {
                await CheckBluetoothConnectedAsync();
                await VerificarSeDispositivoConectadoAsync();

                response = true;
            }
            catch (Exception erro)
            {
                //throw erro;
            }

            return response;
        }

        public static async Task CheckBluetoothConnectedAsync()
        {
            if (!await new BluetoothService().BluetoothConnectAsync())
                throw new Exception("蓝牙未连接");
        }

        public static async Task<bool> VerificarSeDispositivoConectadoAsync(bool verificarConexao = true)
        {
            bool response = false;
            string description = "未连接打印机";
            bool failure = false;
            if (CurrentBluetoothClient == null)
                failure = true;
            else if (CurrentBluetoothClient.PairedDevices == null)
                failure = true;
            else if (CurrentBluetoothClient.PairedDevices.Count() == 0)
                failure = true;
            else if (Stream == null)
                failure = true;
            else if (!CurrentBluetoothClient.Connected && verificarConexao)
                failure = true;
            else if (!FoundPrinter)
                failure = true;
            if (failure)
                throw new Exception(description);
            response = true;
            await Task.Delay(0);
            return response;
        }

        private static async Task<List<byte[]>> QuebrarBytesEmBlocosAsync(byte[] dados, int chunkSize)
        {
            List<byte[]> chunks = new List<byte[]>();
            int start = 0;
            while (start < dados.Length)
            {
                int chunkLength = Math.Min(chunkSize, dados.Length - start);
                byte[] chunk = new byte[chunkLength];
                Array.Copy(dados, start, chunk, 0, chunkLength);
                chunks.Add(chunk);
                start += chunkSize;
            }
            await Task.Delay(0);
            return chunks;
        }
    }
}